package gbench.sandbox.tuple;

import org.junit.jupiter.api.Test;

import static gbench.common.matlib.MatlibCanvas.println;

import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.text.MessageFormat;
import java.util.*;
import java.util.function.Supplier;

/**
 * JunitLisp 列表计算
 * 
 * @author gbench
 *
 */
public class JunitLisp {

    /**
     * Lisp 结构,自定义一个可计算列表 <br>
     * 嵌套列表即列表
     * 
     * @author gbench
     *
     * @param <T> 列表元素
     */
    static class Lisp<T> extends LinkedList<T> {
        private static final long serialVersionUID = 1L;

        /**
         * 元素计算
         * 
         * @return
         */
        public Object evaluate() {
            final var args = this.stream()
                    .map(e -> (e instanceof Lisp) ? ((Lisp<?>) e).evaluate() : (e + "").toUpperCase()) // 列表结算
                    .collect(Collectors.toList()); // 组装成参数
            final var car = args.get(0); // 命令
            final var cdr = args.subList(1, args.size()); // 参数
            
            return MessageFormat.format("({1},{0})", car, cdr);
        } // evaluate

        /**
         * 归集器
         * 
         * @return Lisp 结构
         */
        @SuppressWarnings("unchecked")
        public static <T> Collector<T, ?, Lisp<T>> lpclc() {
            return Collector.of((Supplier<Lisp<T>>) Lisp::new, Lisp::add, (left, right) -> {
                left.addAll(right);
                return left;
            }, lp -> lp.size() == 1 && lp.get(0) instanceof Lisp ? (Lisp<T>) lp.get(0) : lp); // 避免出现[[lisp]]这样的嵌套结构
        }
    }

    /**
     * 层级计算:	([A, ([B, ([C, ([D, E],-), F, G],*)],/), H, ([I, J],+)],+) <br>
     *  | +	----------->	[1=+] <br>
     *  | a	----------->	[1=a] <br>
     *  |  | /	----------->	[1=a, 2=/] <br>
     *  |  | b	----------->	[1=a, 2=b] <br>
     *  |  |  | *	----------->	[1=a, 2=b, 3=*] <br>
     *  |  |  | c	----------->	[1=a, 2=b, 3=c] <br>
     *  |  |  |  | -	----------->	[1=a, 2=b, 3=c, 4=-] <br>
     *  |  |  |  | d	----------->	[1=a, 2=b, 3=c, 4=d] <br>
     *  |  |  |  | e	----------->	[1=a, 2=b, 3=c, 4=e] <br>
     *  |  |  | f	----------->	[1=a, 2=b, 3=f] <br>
     *  |  |  | g	----------->	[1=a, 2=b, 3=g] <br>
     *  | h	----------->	[1=h] <br>
     *  |  | +	----------->	[1=h, 2=+] <br>
     *  |  | i	----------->	[1=h, 2=i] <br>
     *  |  | j	----------->	[1=h, 2=j] <br>
     */
    @SuppressWarnings("unchecked")
    @Test
    public void foo() {
        final var statement = "(+ a (/ b (* c (- d e) f g)) h (+ i j))".split(""); // 表达式语句
        final var BEGIN = "("; // 层级分组的开始符号
        final var END = ")"; // 层级分组的结束符号
        final var root = Stream.of(statement) // 流化处理
                .filter(e -> !e.matches("\\s+")) // 语句解析过滤掉空白字符
                .reduce(new Stack<Object>(), (stack, elem) -> { // 元素读取
                    if (END.equals(elem)) { // 规约开始
                        final var expression = new Lisp<Object>(); // 把层级元素组装成列表节点
                        Stream.iterate(stack.pop(), e -> !(BEGIN.equals(e) || stack.empty()), e -> stack.pop())
                                .forEach(expression::addFirst);
                        stack.push(expression); // 列表节点入栈
                    } else { // 元素读入
                        stack.push(elem); // 元素入栈
                    } // if 元素读取
                    return stack; // 返回堆栈元素
                }, (a, b) -> a).stream().collect(Lisp.lpclc()); // 归结为根节点

        println("层级计算:", root.evaluate());

        final Object LEVEL_SEPRATOR = null; // 阶层分隔符
        final var stack = new Stack<Object>(); // 遍历堆栈
        final var levelMap = new TreeMap<Integer, Object>(); // 层级结构, [0,1,2,...,level] level 起以前的节点刚好是level的全路径。
        var level = 0; // 初始层级

        stack.push(root); // 根节点入栈
        while (!stack.empty()) {
            final var elem = stack.pop(); // 提取元素

            if (elem instanceof Lisp) { // 复合节点，即 列表节点
                final var elems = new LinkedList<Object>();

                ((Lisp<Object>) elem).forEach(elems::addFirst);
                elems.addFirst(LEVEL_SEPRATOR); // 以null为列表结束标记
                elems.forEach(stack::push); // 层级元素入栈
                level++; // 比较层次
            } else { // 单纯节点
                if (elem != LEVEL_SEPRATOR) { // 元素普通元素
                    levelMap.put(level, elem); // 层级元素入栈

                    final var _level = level; // 常量化 level
                    final var path = levelMap.entrySet().stream() // 层级元素的遍历
                            .filter(e -> e.getKey() <= _level) // 提取路径元素，小于当前层级的元素就是就是其父层级
                            .collect(Collectors.toList()); // 提取路径

                    println(" | ".repeat(level) + elem, "----------->", path);
                } else { // 阶层分隔符，该阶层的元素均已处理结束
                    level--; // 层级向前推进。
                } // if elem != null 堆栈层级分割标记
            } // if
        } // while
    } // foo

}
